<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#222" media="(prefers-color-scheme: dark)"><meta name="generator" content="Hexo 6.3.0">
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,300italic,400,400italic,700,700italic%7CZCOOL+QingKe+HuangYou:300,300italic,400,400italic,700,700italic%7CNoto+Sans+Simplified+Chinese:300,300italic,400,400italic,700,700italic%7CJetBrains+Mono:300,300italic,400,400italic,700,700italic&display=swap&subset=latin,latin-ext">

<link rel="stylesheet" href="/lib/@fortawesome/fontawesome-free/css/all.min.css" integrity="sha256-HtsXJanqjKTc8vVQjO4YMhiqFoXkfBsjBWcX91T1jr8=" crossorigin="anonymous">
  <link rel="stylesheet" href="/lib/animate.css/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="/lib/@fancyapps/ui/dist/fancybox/fancybox.css" integrity="sha256-RvRHGSuWAxZpXKV9lLDt2e+rZ+btzn48Wp4ueS3NZKs=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"wyatex.online","root":"/","images":"/images","scheme":"Pisces","darkmode":true,"version":"8.18.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":"mac"},"fold":{"enable":false,"height":500},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":true,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":true}}</script><script src="/js/config.js"></script>

    <meta name="description" content="这章讲解函数类型、类类型、接口类型、类型别名、">
<meta property="og:type" content="article">
<meta property="og:title" content="ts笔记（2）：函数、类、接口类型和类型别名">
<meta property="og:url" content="https://wyatex.online/TypeScript/ts%E7%AC%94%E8%AE%B0%EF%BC%882%EF%BC%89%EF%BC%9A%E5%87%BD%E6%95%B0%E3%80%81%E7%B1%BB%E3%80%81%E6%8E%A5%E5%8F%A3%E7%B1%BB%E5%9E%8B%E5%92%8C%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D/index.html">
<meta property="og:site_name" content="Wyatex&#96;s blog">
<meta property="og:description" content="这章讲解函数类型、类类型、接口类型、类型别名、">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2021-10-31T12:58:14.000Z">
<meta property="article:modified_time" content="2023-05-05T01:25:47.303Z">
<meta property="article:author" content="Wyatex">
<meta property="article:tag" content="前端">
<meta property="article:tag" content="学习笔记">
<meta property="article:tag" content="TypeScript">
<meta name="twitter:card" content="summary">


<link rel="canonical" href="https://wyatex.online/TypeScript/ts%E7%AC%94%E8%AE%B0%EF%BC%882%EF%BC%89%EF%BC%9A%E5%87%BD%E6%95%B0%E3%80%81%E7%B1%BB%E3%80%81%E6%8E%A5%E5%8F%A3%E7%B1%BB%E5%9E%8B%E5%92%8C%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"https://wyatex.online/TypeScript/ts%E7%AC%94%E8%AE%B0%EF%BC%882%EF%BC%89%EF%BC%9A%E5%87%BD%E6%95%B0%E3%80%81%E7%B1%BB%E3%80%81%E6%8E%A5%E5%8F%A3%E7%B1%BB%E5%9E%8B%E5%92%8C%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D/","path":"TypeScript/ts笔记（2）：函数、类、接口类型和类型别名/","title":"ts笔记（2）：函数、类、接口类型和类型别名"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>ts笔记（2）：函数、类、接口类型和类型别名 | Wyatex`s blog</title>
  








  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">Wyatex`s blog</p>
      <i class="logo-line"></i>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签<span class="badge">97</span></a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类<span class="badge">26</span></a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档<span class="badge">155</span></a></li><li class="menu-item menu-item-编程"><a href="/programming/" rel="section"><i class="fa fa-book fa-fw"></i>编程</a></li><li class="menu-item menu-item-蹲坑读物"><a href="/%E5%B9%B2%E8%B4%A7/%E5%BC%80%E5%8F%91%E4%BA%A4%E6%B5%81%E7%BE%A4%E5%88%86%E4%BA%AB%E8%AE%B0%E5%BD%95/" rel="section"><i class="fa fa-book fa-fw"></i>蹲坑读物</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%87%BD%E6%95%B0%E7%B1%BB%E5%9E%8B"><span class="nav-number">1.</span> <span class="nav-text">函数类型</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%BF%94%E5%9B%9E%E5%80%BC%E7%B1%BB%E5%9E%8B"><span class="nav-number">1.1.</span> <span class="nav-text">返回值类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%AF%E7%BC%BA%E7%9C%81%E5%92%8C%E5%8F%AF%E6%8E%A8%E6%96%AD%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%E7%B1%BB%E5%9E%8B"><span class="nav-number">1.2.</span> <span class="nav-text">可缺省和可推断的返回值类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Generator-%E5%87%BD%E6%95%B0%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC"><span class="nav-number">1.3.</span> <span class="nav-text">Generator 函数的返回值</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%AF%E9%80%89%E5%8F%82%E6%95%B0%E5%92%8C%E9%BB%98%E8%AE%A4%E5%8F%82%E6%95%B0"><span class="nav-number">1.4.</span> <span class="nav-text">可选参数和默认参数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%89%A9%E4%BD%99%E5%8F%82%E6%95%B0"><span class="nav-number">1.5.</span> <span class="nav-text">剩余参数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#this"><span class="nav-number">1.6.</span> <span class="nav-text">this</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%87%BD%E6%95%B0%E9%87%8D%E8%BD%BD"><span class="nav-number">1.7.</span> <span class="nav-text">函数重载</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB%E5%9E%8B%E8%B0%93%E8%AF%8D%EF%BC%88is%EF%BC%89"><span class="nav-number">1.8.</span> <span class="nav-text">类型谓词（is）</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E7%B1%BB%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.</span> <span class="nav-text">类类型</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB"><span class="nav-number">2.1.</span> <span class="nav-text">类</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF"><span class="nav-number">2.2.</span> <span class="nav-text">继承</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%85%AC%E5%85%B1%E3%80%81%E7%A7%81%E6%9C%89%E4%B8%8E%E5%8F%97%E4%BF%9D%E6%8A%A4%E7%9A%84%E4%BF%AE%E9%A5%B0%E7%AC%A6"><span class="nav-number">2.3.</span> <span class="nav-text">公共、私有与受保护的修饰符</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%AA%E8%AF%BB%E4%BF%AE%E9%A5%B0%E7%AC%A6"><span class="nav-number">2.4.</span> <span class="nav-text">只读修饰符</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AD%98%E5%8F%96%E5%99%A8"><span class="nav-number">2.5.</span> <span class="nav-text">存取器</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%9D%99%E6%80%81%E5%B1%9E%E6%80%A7"><span class="nav-number">2.6.</span> <span class="nav-text">静态属性</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%8A%BD%E8%B1%A1%E7%B1%BB"><span class="nav-number">2.7.</span> <span class="nav-text">抽象类</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB%E7%9A%84%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.8.</span> <span class="nav-text">类的类型</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E6%8E%A5%E5%8F%A3%E7%B1%BB%E5%9E%8B%E4%B8%8E%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D"><span class="nav-number">3.</span> <span class="nav-text">接口类型与类型别名</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#Interface-%E6%8E%A5%E5%8F%A3%E7%B1%BB%E5%9E%8B"><span class="nav-number">3.1.</span> <span class="nav-text">Interface 接口类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%AF%E7%BC%BA%E7%9C%81%E5%B1%9E%E6%80%A7"><span class="nav-number">3.2.</span> <span class="nav-text">可缺省属性</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%AA%E8%AF%BB%E5%B1%9E%E6%80%A7"><span class="nav-number">3.3.</span> <span class="nav-text">只读属性</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AE%9A%E4%B9%89%E5%87%BD%E6%95%B0%E7%B1%BB%E5%9E%8B"><span class="nav-number">3.4.</span> <span class="nav-text">定义函数类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B4%A2%E5%BC%95%E7%AD%BE%E5%90%8D"><span class="nav-number">3.5.</span> <span class="nav-text">索引签名</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF-1"><span class="nav-number">3.6.</span> <span class="nav-text">继承</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AE%9E%E7%8E%B0"><span class="nav-number">3.7.</span> <span class="nav-text">实现</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Type-%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D"><span class="nav-number">4.</span> <span class="nav-text">Type 类型别名</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#Interface-%E4%B8%8E-Type-%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="nav-number">4.1.</span> <span class="nav-text">Interface 与 Type 的区别</span></a></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="Wyatex"
      src="/images/avatar.jpg">
  <p class="site-author-name" itemprop="name">Wyatex</p>
  <div class="site-description" itemprop="description">这里是我用来做笔记的网站哟~</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">155</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">26</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">97</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author animated">
      <span class="links-of-author-item">
        <a href="https://github.com/wyatex" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;wyatex" rel="noopener me" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:wyatex@qq.com" title="E-Mail → mailto:wyatex@qq.com" rel="noopener me" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
  </div>

        </div>
      </div>
    </div>

    
    <div class="sidebar-inner sidebar-blogroll">
      <div class="links-of-blogroll animated">
        <div class="links-of-blogroll-title"><i class="fa fa-globe fa-fw"></i>
          链接
        </div>
        <ul class="links-of-blogroll-list">
            <li class="links-of-blogroll-item">
              <a href="https://antfu.me/" title="https:&#x2F;&#x2F;antfu.me&#x2F;" rel="noopener" target="_blank">Anthony Fu</a>
            </li>
            <li class="links-of-blogroll-item">
              <a href="https://www.codesky.me/" title="https:&#x2F;&#x2F;www.codesky.me&#x2F;" rel="noopener" target="_blank">CodeSky</a>
            </li>
            <li class="links-of-blogroll-item">
              <a href="https://learn.lianglianglee.com/" title="https:&#x2F;&#x2F;learn.lianglianglee.com&#x2F;" rel="noopener" target="_blank">技术文章摘抄</a>
            </li>
        </ul>
      </div>
    </div>
        <div class="pjax">
        <div class="sidebar-inner sidebar-post-related">
          <div class="animated">
              <div class="links-of-blogroll-title"><i class="fa fa-signs-post fa-fw"></i>
    相关文章
  </div>
  <ul class="popular-posts">
    <li class="popular-posts-item">
      <a class="popular-posts-link" href="/TypeScript/ts%E7%AC%94%E8%AE%B0%EF%BC%883%EF%BC%89%EF%BC%9A%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B%E3%80%81%E4%BA%A4%E5%8F%89%E7%B1%BB%E5%9E%8B%E3%80%81%E6%9E%9A%E4%B8%BE%E7%B1%BB%E5%9E%8B%E3%80%81%E6%B3%9B%E5%9E%8B/" rel="bookmark">
        <time class="popular-posts-time">2021-11-02</time>
        <br>
      ts笔记（3）：联合类型、交叉类型、枚举类型、泛型
      </a>
    </li>
    <li class="popular-posts-item">
      <a class="popular-posts-link" href="/TypeScript/ts%E7%AC%94%E8%AE%B0%EF%BC%881%EF%BC%89%EF%BC%9A%E6%90%AD%E5%BB%BA%E5%92%8C%E4%B8%80%E4%BA%9B%E5%9F%BA%E7%A1%80%E7%B1%BB%E5%9E%8B/" rel="bookmark">
        <time class="popular-posts-time">2021-10-28</time>
        <br>
      ts笔记（1）：搭建和一些基础类型
      </a>
    </li>
    <li class="popular-posts-item">
      <a class="popular-posts-link" href="/TypeScript/ts%E7%AC%94%E8%AE%B0%EF%BC%886%EF%BC%89%EF%BC%9A%E4%BD%BF%E7%94%A8TypeScript%E5%BC%80%E5%8F%91Node.js%E5%BA%94%E7%94%A8/" rel="bookmark">
        <time class="popular-posts-time">2021-11-15</time>
        <br>
      ts笔记（6）：常见TypeScript错误、开发Node.js应用
      </a>
    </li>
    <li class="popular-posts-item">
      <a class="popular-posts-link" href="/TypeScript/ts%E7%AC%94%E8%AE%B0%EF%BC%884%EF%BC%89%EF%BC%9A%E7%B1%BB%E5%9E%8B%E5%AE%88%E5%8D%AB%E3%80%81%E7%B1%BB%E5%9E%8B%E5%85%BC%E5%AE%B9%E3%80%81%E5%A2%9E%E5%BC%BA%E7%B1%BB%E5%9E%8B%E7%B3%BB%E7%BB%9F/" rel="bookmark">
        <time class="popular-posts-time">2021-11-06</time>
        <br>
      ts笔记（4）：类型守卫、类型兼容、增强类型系统
      </a>
    </li>
    <li class="popular-posts-item">
      <a class="popular-posts-link" href="/TypeScript/ts%E7%AC%94%E8%AE%B0%EF%BC%885%EF%BC%89%EF%BC%9A%E5%AE%98%E6%96%B9%E5%B7%A5%E5%85%B7%E7%B1%BB%E3%80%81%E6%89%93%E9%80%A0%E8%87%AA%E5%B7%B1%E7%9A%84%E5%B7%A5%E5%85%B7%E7%B1%BB%E5%9E%8B/" rel="bookmark">
        <time class="popular-posts-time">2021-11-13</time>
        <br>
      ts笔记（5）：官方工具类、打造自己的工具类型
      </a>
    </li>
  </ul>

          </div>
        </div>
        </div>
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://wyatex.online/TypeScript/ts%E7%AC%94%E8%AE%B0%EF%BC%882%EF%BC%89%EF%BC%9A%E5%87%BD%E6%95%B0%E3%80%81%E7%B1%BB%E3%80%81%E6%8E%A5%E5%8F%A3%E7%B1%BB%E5%9E%8B%E5%92%8C%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.jpg">
      <meta itemprop="name" content="Wyatex">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Wyatex`s blog">
      <meta itemprop="description" content="这里是我用来做笔记的网站哟~">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="ts笔记（2）：函数、类、接口类型和类型别名 | Wyatex`s blog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          ts笔记（2）：函数、类、接口类型和类型别名
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2021-10-31 20:58:14" itemprop="dateCreated datePublished" datetime="2021-10-31T20:58:14+08:00">2021-10-31</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-05-05 09:25:47" itemprop="dateModified" datetime="2023-05-05T09:25:47+08:00">2023-05-05</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/TypeScript/" itemprop="url" rel="index"><span itemprop="name">TypeScript</span></a>
        </span>
    </span>

  
    <span class="post-meta-item" title="阅读次数" id="busuanzi_container_page_pv">
      <span class="post-meta-item-icon">
        <i class="far fa-eye"></i>
      </span>
      <span class="post-meta-item-text">阅读次数：</span>
      <span id="busuanzi_value_page_pv"></span>
    </span>
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody"><p>这章讲解函数类型、类类型、接口类型、类型别名、</p>
<span id="more"></span>

<h1 id="函数类型"><a href="#函数类型" class="headerlink" title="函数类型"></a>函数类型</h1><p>在 TypeScript 里我们可以显式指定函数参数和返回值的类型，如下：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> add = (<span class="attr">a</span>: <span class="built_in">number</span>, <span class="attr">b</span>: <span class="built_in">number</span>): <span class="function"><span class="params">number</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> a + b</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="返回值类型"><a href="#返回值类型" class="headerlink" title="返回值类型"></a>返回值类型</h2><p>在 JavaScript 中，我们知道一个函数可以没有显式 return，此时函数的返回值应该是 undefined，而<strong>函数的返回类型是 void 类型</strong>。</p>
<blockquote>
<p>需要注意的是，在 TypeScript 中，如果我们显式声明函数的返回值类型为 undfined，将会得到如下所示的错误提醒。</p>
</blockquote>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ts(2355) A function whose declared type is neither &#x27;void&#x27; nor &#x27;any&#x27; must return a value</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>): <span class="literal">undefined</span> &#123;</span><br><span class="line">  <span class="comment">// TODO</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>按照上一章，如果函数不需要返回值应该使用 void 来表示返回值类型，这应该算是 void 类型的唯一用处了。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn1</span>(<span class="params"></span>): <span class="built_in">void</span> &#123;&#125;</span><br><span class="line"><span class="title function_">fn1</span>().<span class="title function_">doSomething</span>() <span class="comment">// ts(2339) Property &#x27;doSomething&#x27; does not exist on type &#x27;void&#x27;.</span></span><br></pre></td></tr></table></figure>

<p>我们可以使用类似定义箭头函数的语法来表示函数类型的参数和返回值类型，此时&#x3D;&gt; 类型仅仅用来定义一个函数类型而不用实现这个函数。<strong>需要注意的是，这里的&#x3D;&gt;与 ES6 中箭头函数的&#x3D;&gt;有所不同。TypeScript 函数类型中的&#x3D;&gt;用来表示函数的定义，其左侧是函数的参数类型，右侧是函数的返回值类型；而 ES6 中的&#x3D;&gt;是函数的实现</strong>。如下：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> <span class="title class_">Adder</span> = <span class="function">(<span class="params">a: <span class="built_in">number</span>, b: <span class="built_in">number</span></span>) =&gt;</span> <span class="built_in">number</span> <span class="comment">// TypeScript 函数类型定义</span></span><br><span class="line"><span class="keyword">const</span> <span class="attr">add</span>: <span class="title class_">Adder</span> = <span class="function">(<span class="params">a, b</span>) =&gt;</span> a + b <span class="comment">// ES6 箭头函数</span></span><br></pre></td></tr></table></figure>

<p>在对象中，除了使用这种声明语法，我们还可以使用类似对象属性的简写语法来声明函数类型的属性，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">Entity</span> &#123;</span><br><span class="line">  <span class="attr">add</span>: <span class="function">(<span class="params">a: <span class="built_in">number</span>, b: <span class="built_in">number</span></span>) =&gt;</span> <span class="built_in">number</span></span><br><span class="line">  <span class="title function_">del</span>(<span class="attr">a</span>: <span class="built_in">number</span>, <span class="attr">b</span>: <span class="built_in">number</span>): <span class="built_in">number</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> <span class="attr">entity</span>: <span class="title class_">Entity</span> = &#123;</span><br><span class="line">  <span class="attr">add</span>: <span class="function">(<span class="params">a, b</span>) =&gt;</span> a + b,</span><br><span class="line">  <span class="title function_">del</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> a - b</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="可缺省和可推断的返回值类型"><a href="#可缺省和可推断的返回值类型" class="headerlink" title="可缺省和可推断的返回值类型"></a>可缺省和可推断的返回值类型</h2><p>幸运的是，函数返回值的类型可以在 TypeScript 中被推断出来，即可缺省。</p>
<p>函数内是一个相对独立的上下文环境，我们可以根据入参对值加工计算，并返回新的值。从类型层面看，我们也可以通过类型推断（回想一下 04 讲中的类型推断、上下文类型推断）加工计算入参的类型，并返回新的类型，示例如下：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">computeTypes</span>(<span class="params">one: <span class="built_in">string</span>, two: <span class="built_in">number</span></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> nums = [two]</span><br><span class="line">  <span class="keyword">const</span> strs = [one]</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    nums,</span><br><span class="line">    strs,</span><br><span class="line">  &#125; <span class="comment">// 返回 &#123; nums: number[]; strs: string[] &#125; 的类型</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>一般情况下，TypeScript 中的函数返回值类型是可以缺省和推断出来的，但是有些特例需要我们显式声明返回值类型，比如 Generator 函数的返回值。</p>
<h2 id="Generator-函数的返回值"><a href="#Generator-函数的返回值" class="headerlink" title="Generator 函数的返回值"></a>Generator 函数的返回值</h2><p>Generator 函数返回的是一个 Iterator 迭代器对象，我们可以使用 Generator 的同名接口泛型或者 Iterator 的同名接口泛型表示返回值的类型，示例如下：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> <span class="title class_">AnyType</span> = <span class="built_in">boolean</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">AnyReturnType</span> = <span class="built_in">string</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">AnyNextType</span> = <span class="built_in">number</span></span><br><span class="line"><span class="keyword">function</span>* <span class="title function_">gen</span>(): <span class="title class_">Generator</span>&lt;<span class="title class_">AnyType</span>, <span class="title class_">AnyReturnType</span>, <span class="title class_">AnyNextType</span>&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> nextValue = <span class="keyword">yield</span> <span class="literal">true</span> <span class="comment">// nextValue 类型是 number，yield 后必须是 boolean 类型</span></span><br><span class="line">  <span class="keyword">return</span> <span class="string">`<span class="subst">$&#123;nextValue&#125;</span>`</span> <span class="comment">// 必须返回 string 类型</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="可选参数和默认参数"><a href="#可选参数和默认参数" class="headerlink" title="可选参数和默认参数"></a>可选参数和默认参数</h2><p>在实际情况中可能会遇到函数参数可以可传或不传的情况，在 ts 中也一样可以表达</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">log</span>(<span class="params">x?: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">  <span class="comment">// function log(x?: string | undefined): string | undefined</span></span><br><span class="line">  <span class="keyword">return</span> x</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">log</span>() <span class="comment">// =&gt; undefined</span></span><br><span class="line"><span class="title function_">log</span>(<span class="string">&#x27;hello world&#x27;</span>) <span class="comment">// =&gt; hello world</span></span><br></pre></td></tr></table></figure>

<p>如果在类型标注的<code>:</code>前加上<code>?</code>表示 log 函数的参数 x 就是可缺省的，也就是说 x 的类型可能是<code>undefined</code></p>
<p>但是并不意味着可缺省和类型是 <code>undefined</code> 等价的：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">log</span>(<span class="params">x?: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(x)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">log1</span>(<span class="params">x: <span class="built_in">string</span> | <span class="literal">undefined</span></span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(x)</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">log</span>()</span><br><span class="line"><span class="title function_">log</span>(<span class="literal">undefined</span>)</span><br><span class="line"><span class="title function_">log1</span>() <span class="comment">// ts(2554) Expected 1 arguments, but got 0</span></span><br><span class="line"><span class="title function_">log1</span>(<span class="literal">undefined</span>)</span><br></pre></td></tr></table></figure>

<p>显然这里的<code>?:</code>表示参数可以缺省、可以不传，也就是说调用函数时，我们可以不显式传入参数。但是，如果我们声明了参数类型为 xxx | undefined，就表示函数参数是不可缺省且类型必须是 xxx 或者 undfined。</p>
<p>在 ES6 中支持函数默认参数的功能，而 TypeScript 会根据函数的默认参数的类型来推断函数参数的类型，示例如下：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">log</span>(<span class="params">x = <span class="string">&#x27;hello&#x27;</span></span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(x)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="title function_">log</span>() <span class="comment">// =&gt; &#x27;hello&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="title function_">log</span>(<span class="string">&#x27;hi&#x27;</span>) <span class="comment">// =&gt; &#x27;hi&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="title function_">log</span>(<span class="number">1</span>) <span class="comment">// ts(2345) Argument of type &#x27;1&#x27; is not assignable to parameter of type &#x27;string | undefined&#x27;</span></span><br></pre></td></tr></table></figure>

<p>在上述示例中，根据函数的默认参数 ‘hello’ ，TypeScript 推断出了 x 的类型为 string | undefined。</p>
<h2 id="剩余参数"><a href="#剩余参数" class="headerlink" title="剩余参数"></a>剩余参数</h2><p>在 ES6 中，JavaScript 支持函数参数的剩余参数，它可以把多个参数收集到一个变量中。同样，在 TypeScript 中也支持这样的参数类型定义，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">sum</span>(<span class="params">...nums: <span class="built_in">number</span>[]</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> nums.<span class="title function_">reduce</span>(<span class="function">(<span class="params">a, b</span>) =&gt;</span> a + b, <span class="number">0</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="title function_">sum</span>(<span class="number">1</span>, <span class="number">2</span>) <span class="comment">// =&gt; 3</span></span><br><span class="line"></span><br><span class="line"><span class="title function_">sum</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>) <span class="comment">// =&gt; 6</span></span><br><span class="line"></span><br><span class="line"><span class="title function_">sum</span>(<span class="number">1</span>, <span class="string">&#x27;2&#x27;</span>) <span class="comment">// ts(2345) Argument of type &#x27;string&#x27; is not assignable to parameter of type &#x27;number&#x27;</span></span><br></pre></td></tr></table></figure>

<p>如果我们将函数参数 nums 聚合的类型定义为 (number | string)[]，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">sum</span>(<span class="params">...nums: (<span class="built_in">number</span> | <span class="built_in">string</span>)[]</span>): <span class="built_in">number</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> nums.<span class="property">reduce</span>&lt;<span class="built_in">number</span>&gt;(<span class="function">(<span class="params">a, b</span>) =&gt;</span> a + <span class="title class_">Number</span>(b), <span class="number">0</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="title function_">sum</span>(<span class="number">1</span>, <span class="string">&#x27;2&#x27;</span>, <span class="number">3</span>) <span class="comment">// 6</span></span><br></pre></td></tr></table></figure>

<p>那么，函数的每一个参数的类型就是联合类型 number | string，因此 sum(1, ‘2’, 3) 的类型检查也就通过了。</p>
<h2 id="this"><a href="#this" class="headerlink" title="this"></a>this</h2><p>使用了 TypeScript 后，通过指定 this 的类型（严格模式下，必须显式指定 this 的类型），当我们错误使用了 this，TypeScript 就会提示我们，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">say</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span>) <span class="comment">// ts(2683) &#x27;this&#x27; implicitly has type &#x27;any&#x27; because it does not have a type annotation</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">say</span>()</span><br></pre></td></tr></table></figure>

<p>在上述代码中，如果我们直接调用 say 函数，this 可能指向全局 window 或 global（Node 中）或 undefined（浏览器 js 脚本开启 strict）。但是，在 strict 模式下的 TypeScript 中，它会提示 this 的类型是 any，此时就需要我们手动显式指定类型了。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">say</span>(<span class="params"><span class="variable language_">this</span>: Window, name: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">window</span>.<span class="property">say</span> = say</span><br><span class="line"></span><br><span class="line"><span class="variable language_">window</span>.<span class="title function_">say</span>(<span class="string">&#x27;hi&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> obj = &#123;</span><br><span class="line">  say,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">obj.<span class="title function_">say</span>(<span class="string">&#x27;hi&#x27;</span>) <span class="comment">// ts(2684) The &#x27;this&#x27; context of type &#x27;&#123; say: (this: Window, name: string) =&gt; void; &#125;&#x27; is not assignable to method&#x27;s &#x27;this&#x27; of type &#x27;Window&#x27;.</span></span><br><span class="line"></span><br><span class="line"><span class="title function_">say</span>(<span class="string">&#x27;captain&#x27;</span>) <span class="comment">// ts(2684) The &#x27;this&#x27; context of type &#x27;void&#x27; is not assignable to method&#x27;s &#x27;this&#x27; of type &#x27;Window&#x27;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>需要注意的是，如果我们直接调用 say()，this 实际上应该指向全局变量 window，但是因为 TypeScript 无法确定 say 函数被谁调用，所以将 this 的指向默认为 void，也就提示了一个 ts(2684) 错误。</p>
</blockquote>
<p>同样，定义对象的函数属性时，只要实际调用中 this 的指向与指定的 this 指向不同，TypeScript 就能发现 this 指向的错误，示例代码如下：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">Person</span> &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">  <span class="title function_">say</span>(<span class="attr">this</span>: <span class="title class_">Person</span>): <span class="built_in">void</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="attr">person</span>: <span class="title class_">Person</span> = &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;captain&#x27;</span>,</span><br><span class="line">  <span class="title function_">say</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span>)</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> fn = person.<span class="property">say</span></span><br><span class="line"><span class="title function_">fn</span>() <span class="comment">// ts(2684) The &#x27;this&#x27; context of type &#x27;void&#x27; is not assignable to method&#x27;s &#x27;this&#x27; of type &#x27;Person&#x27;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>注意：显式注解函数中的 this 类型，它表面上占据了第一个形参的位置，但并不意味着函数真的多了一个参数，因为 TypeScript 转译为 JavaScript 后，“伪形参” this 会被抹掉。</p>
</blockquote>
<p>同样，我们也可以显式限定类函数属性中的 this 类型，TypeScript 也能检查出错误的使用方式，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Component</span> &#123;</span><br><span class="line">  <span class="title function_">onClick</span>(<span class="params"><span class="variable language_">this</span>: Component</span>) &#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> component = <span class="keyword">new</span> <span class="title class_">Component</span>()</span><br><span class="line"><span class="keyword">interface</span> UI &#123;</span><br><span class="line">  <span class="title function_">addClickListener</span>(<span class="attr">onClick</span>: <span class="function">(<span class="params"><span class="variable language_">this</span>: <span class="built_in">void</span></span>) =&gt;</span> <span class="built_in">void</span>): <span class="built_in">void</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> <span class="attr">ui</span>: <span class="variable constant_">UI</span> = &#123;</span><br><span class="line">  <span class="title function_">addClickListener</span>(<span class="params"></span>) &#123;&#125;,</span><br><span class="line">&#125;</span><br><span class="line">ui.<span class="title function_">addClickListener</span>(<span class="keyword">new</span> <span class="title class_">Component</span>().<span class="property">onClick</span>) <span class="comment">// ts(2345)</span></span><br></pre></td></tr></table></figure>

<p>此外，在链式调用风格的库中，使用 this 也可以很方便地表达出其类型，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Container</span> &#123;</span><br><span class="line">  <span class="keyword">private</span> <span class="attr">val</span>: <span class="built_in">number</span></span><br><span class="line"></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">val: <span class="built_in">number</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">val</span> = val</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">map</span>(<span class="attr">cb</span>: <span class="function">(<span class="params">x: <span class="built_in">number</span></span>) =&gt;</span> <span class="built_in">number</span>): <span class="variable language_">this</span> &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">val</span> = <span class="title function_">cb</span>(<span class="variable language_">this</span>.<span class="property">val</span>)</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">log</span>(): <span class="variable language_">this</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">val</span>)</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> instance = <span class="keyword">new</span> <span class="title class_">Container</span>(<span class="number">1</span>)</span><br><span class="line">  .<span class="title function_">map</span>(<span class="function">(<span class="params">x</span>) =&gt;</span> x + <span class="number">1</span>)</span><br><span class="line">  .<span class="title function_">log</span>() <span class="comment">// =&gt; 2</span></span><br><span class="line">  .<span class="title function_">map</span>(<span class="function">(<span class="params">x</span>) =&gt;</span> x * <span class="number">3</span>)</span><br><span class="line">  .<span class="title function_">log</span>() <span class="comment">// =&gt; 6</span></span><br></pre></td></tr></table></figure>

<p>因为 Container 类中 map、log 等函数属性（方法）未显式指定 this 类型，默认类型是 Container，所以以上方法在被调用时返回的类型也是 Container，this 指向一直是类的实例，它可以一直无限地被链式调用。</p>
<h2 id="函数重载"><a href="#函数重载" class="headerlink" title="函数重载"></a>函数重载</h2><p>下面代码通过 convert 函数将 string 类型的值转换为 number 类型，number 类型转换为 string 类型，而将 null 类型转换为数字 -1。此时， x1、x2、x3 的返回值类型都会被推断成 string | number</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">convert</span>(<span class="params">x: <span class="built_in">string</span> | <span class="built_in">number</span> | <span class="literal">null</span></span>): <span class="built_in">string</span> | <span class="built_in">number</span> | -<span class="number">1</span> &#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> x === <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Number</span>(x)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> x === <span class="string">&#x27;number&#x27;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">String</span>(x)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> -<span class="number">1</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> x1 = <span class="title function_">convert</span>(<span class="string">&#x27;1&#x27;</span>) <span class="comment">// =&gt; string | number</span></span><br><span class="line"><span class="keyword">const</span> x2 = <span class="title function_">convert</span>(<span class="number">1</span>) <span class="comment">// =&gt; string | number</span></span><br><span class="line"><span class="keyword">const</span> x3 = <span class="title function_">convert</span>(<span class="literal">null</span>) <span class="comment">// =&gt; string | number</span></span><br></pre></td></tr></table></figure>

<p>如果想要精确的描述参数和返回值关系的话，就需要用到函数重载。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">convert</span>(<span class="params">x: <span class="built_in">string</span></span>): <span class="built_in">number</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">convert</span>(<span class="params">x: <span class="built_in">number</span></span>): <span class="built_in">string</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">convert</span>(<span class="params">x: <span class="literal">null</span></span>): -<span class="number">1</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">convert</span>(<span class="params">x: <span class="built_in">string</span> | <span class="built_in">number</span> | <span class="literal">null</span></span>): <span class="built_in">any</span> &#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> x === <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Number</span>(x)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> x === <span class="string">&#x27;number&#x27;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">String</span>(x)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> -<span class="number">1</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> x1 = <span class="title function_">convert</span>(<span class="string">&#x27;1&#x27;</span>) <span class="comment">// =&gt; number</span></span><br><span class="line"><span class="keyword">const</span> x2 = <span class="title function_">convert</span>(<span class="number">1</span>) <span class="comment">// =&gt; string</span></span><br><span class="line"><span class="keyword">const</span> x3 = <span class="title function_">convert</span>(<span class="literal">null</span>) <span class="comment">// -1</span></span><br></pre></td></tr></table></figure>

<p>示例中 1~3 行定义了三种各不相同的函数类型列表，并描述了不同的参数类型对应不同的返回值类型，而从第 4 行开始才是函数的实现。</p>
<blockquote>
<p>注意：函数重载列表的各个成员（即示例中的 1 ~ 3 行）必须是函数实现（即示例中的第 4 行）的子集，例如 “function convert(x: string): number”是“function convert(x: string | number | null): any”的子集。</p>
</blockquote>
<p>在 convert 函数被调用时，TypeScript 会从上到下查找函数重载列表中与入参类型匹配的类型，并优先使用第一个匹配的重载定义。因此，我们需要把最精确的函数重载放到前面。比如下面实例：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> P1 &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">interface</span> P2 <span class="keyword">extends</span> P1 &#123;</span><br><span class="line">  <span class="attr">age</span>: <span class="built_in">number</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">convert</span>(<span class="params">x: P1</span>): <span class="built_in">number</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">convert</span>(<span class="params">x: P2</span>): <span class="built_in">string</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">convert</span>(<span class="params">x: P1 | P2</span>): <span class="built_in">any</span> &#123;&#125;</span><br><span class="line"><span class="keyword">const</span> x1 = <span class="title function_">convert</span>(&#123; <span class="attr">name</span>: <span class="string">&#x27;&#x27;</span> &#125; <span class="keyword">as</span> <span class="variable constant_">P1</span>) <span class="comment">// =&gt; number</span></span><br><span class="line"><span class="keyword">const</span> x2 = <span class="title function_">convert</span>(&#123; <span class="attr">name</span>: <span class="string">&#x27;&#x27;</span>, <span class="attr">age</span>: <span class="number">18</span> &#125; <span class="keyword">as</span> <span class="variable constant_">P2</span>) <span class="comment">// number</span></span><br></pre></td></tr></table></figure>

<p>因为 P2 继承自 P1，所以类型为 P2 的参数会和类型为 P1 的参数一样匹配到第一个函数重载，此时 x1、x2 的返回值都是 number。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">convert</span>(<span class="params">x: P2</span>): <span class="built_in">string</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">convert</span>(<span class="params">x: P1</span>): <span class="built_in">number</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">convert</span>(<span class="params">x: P1 | P2</span>): <span class="built_in">any</span> &#123;&#125;</span><br><span class="line"><span class="keyword">const</span> x1 = <span class="title function_">convert</span>(&#123; <span class="attr">name</span>: <span class="string">&#x27;&#x27;</span> &#125; <span class="keyword">as</span> <span class="variable constant_">P1</span>) <span class="comment">// =&gt; number</span></span><br><span class="line"><span class="keyword">const</span> x2 = <span class="title function_">convert</span>(&#123; <span class="attr">name</span>: <span class="string">&#x27;&#x27;</span>, <span class="attr">age</span>: <span class="number">18</span> &#125; <span class="keyword">as</span> <span class="variable constant_">P2</span>) <span class="comment">// =&gt; string</span></span><br></pre></td></tr></table></figure>

<p>而我们只需要将函数重载列表的顺序调换一下，类型为 P2 和 P1 的参数就可以分别匹配到正确的函数重载了</p>
<h2 id="类型谓词（is）"><a href="#类型谓词（is）" class="headerlink" title="类型谓词（is）"></a>类型谓词（is）</h2><p>示例：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">isString</span>(<span class="params">s</span>): s is <span class="built_in">string</span> &#123;</span><br><span class="line">  <span class="comment">// 类型谓词</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">typeof</span> s === <span class="string">&#x27;string&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">isNumber</span>(<span class="params">n: <span class="built_in">number</span></span>): <span class="built_in">boolean</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">typeof</span> n === <span class="string">&#x27;number&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">operator</span>(<span class="params">x: <span class="built_in">unknown</span></span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="title function_">isString</span>(x)) &#123;</span><br><span class="line">    <span class="comment">// ok x 类型缩小为 string</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (<span class="title function_">isNumber</span>(x)) &#123;</span><br><span class="line">    <span class="comment">// ts(2345) unknown 不能赋值给 number</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="类类型"><a href="#类类型" class="headerlink" title="类类型"></a>类类型</h1><h2 id="类"><a href="#类" class="headerlink" title="类"></a>类</h2><p>在实际业务中，任何实体都可以被抽象为一个使用类表达的类似对象的数据结构，且这个数据结构既包含属性，又包含方法，比如我们在下方抽象了一个狗的类。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Dog</span> &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">name: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">name</span> = name</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">bark</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Woof! Woof!&#x27;</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> dog = <span class="keyword">new</span> <span class="title class_">Dog</span>(<span class="string">&#x27;Q&#x27;</span>)</span><br><span class="line">dog.<span class="title function_">bark</span>() <span class="comment">// =&gt; &#x27;Woof! Woof!&#x27;</span></span><br></pre></td></tr></table></figure>

<p>如果使用传统的 ES5 或者 ES3 代码定义类，我们需要使用函数+原型链的形式进行模拟，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Dog</span>(<span class="params">name: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">name</span> = name <span class="comment">// ts(2683) &#x27;this&#x27; implicitly has type &#x27;any&#x27; because it does not have a type annotation.</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">Dog</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">bark</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Woof! Woof!&#x27;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> dog = <span class="keyword">new</span> <span class="title class_">Dog</span>(<span class="string">&#x27;Q&#x27;</span>) <span class="comment">// ts(7009) &#x27;new&#x27; expression, whose target lacks a construct signature, implicitly has an &#x27;any&#x27; type.</span></span><br><span class="line">dog.<span class="title function_">bark</span>() <span class="comment">// =&gt; &#x27;Woof! Woof!&#x27;</span></span><br></pre></td></tr></table></figure>

<h2 id="继承"><a href="#继承" class="headerlink" title="继承"></a>继承</h2><p>在 TypeScript 中，使用 extends 关键字就能很方便地定义类继承的抽象模式，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span> &#123;</span><br><span class="line">  <span class="keyword">type</span> = <span class="string">&#x27;Animal&#x27;</span></span><br><span class="line"></span><br><span class="line">  <span class="title function_">say</span>(<span class="params">name: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`I&#x27;m <span class="subst">$&#123;name&#125;</span>!`</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Dog</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Animal</span> &#123;</span><br><span class="line">  <span class="title function_">bark</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Woof! Woof!&#x27;</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> dog = <span class="keyword">new</span> <span class="title class_">Dog</span>()</span><br><span class="line">dog.<span class="title function_">bark</span>() <span class="comment">// =&gt; &#x27;Woof! Woof!&#x27;</span></span><br><span class="line">dog.<span class="title function_">say</span>(<span class="string">&#x27;Q&#x27;</span>) <span class="comment">// =&gt; I&#x27;m Q!</span></span><br><span class="line">dog.<span class="property">type</span> <span class="comment">// =&gt; Animal</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>说明：派生类通常被称作子类，基类也被称作超类（或者父类）。</p>
</blockquote>
<blockquote>
<p>这里的 Dog 基类与第一个例子中的类相比，少了一个构造函数。<strong>这是因为派生类如果包含一个构造函数，则必须在构造函数中调用 super() 方法，这是 TypeScript 强制执行的一条重要规则</strong>。</p>
</blockquote>
<p>如果不调用 super：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Dog</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Animal</span> &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">name: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">    <span class="comment">// ts(2377) Constructors for derived classes must contain a &#x27;super&#x27; call.</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">name</span> = name</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">bark</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Woof! Woof!&#x27;</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="公共、私有与受保护的修饰符"><a href="#公共、私有与受保护的修饰符" class="headerlink" title="公共、私有与受保护的修饰符"></a>公共、私有与受保护的修饰符</h2><p>属性和方法除了可以通过 extends 被继承之外，还可以通过修饰符控制可访问性。在 TypeScript 中就支持 3 种访问修饰符，分别是 public、private、protected。</p>
<ul>
<li>public 修饰的是在任何地方可见、公有的属性或方法；</li>
<li>private 修饰的是仅在同一类中可见、私有的属性或方法；</li>
<li>protected 修饰的是仅在类自身及子类中可见、受保护的属性或方法。</li>
</ul>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Son</span> &#123;</span><br><span class="line">  <span class="keyword">public</span> <span class="attr">firstName</span>: <span class="built_in">string</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="attr">lastName</span>: <span class="built_in">string</span> = <span class="string">&#x27;Stark&#x27;</span></span><br><span class="line"></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">firstName: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">firstName</span> = firstName</span><br><span class="line"></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">lastName</span> <span class="comment">// ok</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> son = <span class="keyword">new</span> <span class="title class_">Son</span>(<span class="string">&#x27;Tony&#x27;</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(son.<span class="property">firstName</span>) <span class="comment">//  =&gt; &quot;Tony&quot;</span></span><br><span class="line">son.<span class="property">firstName</span> = <span class="string">&#x27;Jack&#x27;</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(son.<span class="property">firstName</span>) <span class="comment">//  =&gt; &quot;Jack&quot;</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(son.<span class="property">lastName</span>) <span class="comment">// ts(2341) Property &#x27;lastName&#x27; is private and only accessible within class &#x27;Son&#x27;.</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>注意：TypeScript 中定义类的私有属性仅仅代表静态类型检测层面的私有。如果我们强制忽略 TypeScript 类型的检查错误，转译且运行 JavaScript 时依旧可以获取到 lastName 属性，这是因为 JavaScript 并不支持真正意义上的私有属性。</p>
</blockquote>
<p>接下来我们再看一下受保护的属性和方法，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Son</span> &#123;</span><br><span class="line">  <span class="keyword">public</span> <span class="attr">firstName</span>: <span class="built_in">string</span></span><br><span class="line">  <span class="keyword">protected</span> <span class="attr">lastName</span>: <span class="built_in">string</span> = <span class="string">&#x27;Stark&#x27;</span></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">firstName: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">firstName</span> = firstName</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">lastName</span> <span class="comment">// ok</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">GrandSon</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Son</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">firstName: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">super</span>(firstName)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="title function_">getMyLastName</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">lastName</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> grandSon = <span class="keyword">new</span> <span class="title class_">GrandSon</span>(<span class="string">&#x27;Tony&#x27;</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(grandSon.<span class="title function_">getMyLastName</span>()) <span class="comment">// =&gt; &quot;Stark&quot;</span></span><br><span class="line">grandSon.<span class="property">lastName</span> <span class="comment">// ts(2445) Property &#x27;lastName&#x27; is protected and only accessible within class &#x27;Son&#x27; and its subclasses.</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>虽然我们不能通过派生类的实例访问 protected 修饰的属性和方法，但是可以通过派生类的实例方法进行访问。比如示例中的第 21 行，通过实例的 getMyLastName 方法获取受保护的属性 lastName 是 ok 的，而第 22 行通过实例直接获取受保护的属性 lastName 则提示了一个 ts(2445) 的错误。</p>
</blockquote>
<h2 id="只读修饰符"><a href="#只读修饰符" class="headerlink" title="只读修饰符"></a>只读修饰符</h2><p>在前面的例子中，Son 类 public 修饰的属性既公开可见，又可以更改值，如果我们不希望类的属性被更改，则可以使用 readonly 只读修饰符声明类的属性，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Son</span> &#123;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">readonly</span> <span class="attr">firstName</span>: <span class="built_in">string</span></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">firstName: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">firstName</span> = firstName</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> son = <span class="keyword">new</span> <span class="title class_">Son</span>(<span class="string">&#x27;Tony&#x27;</span>)</span><br><span class="line">son.<span class="property">firstName</span> = <span class="string">&#x27;Jack&#x27;</span> <span class="comment">// ts(2540) Cannot assign to &#x27;firstName&#x27; because it is a read-only property.</span></span><br></pre></td></tr></table></figure>

<h2 id="存取器"><a href="#存取器" class="headerlink" title="存取器"></a>存取器</h2><p>除了上边提到的修饰符之外，在 TypeScript 中还可以通过 getter、setter 截取对类成员的读写访问。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Son</span> &#123;</span><br><span class="line">  <span class="keyword">public</span> <span class="attr">firstName</span>: <span class="built_in">string</span></span><br><span class="line">  <span class="keyword">protected</span> <span class="attr">lastName</span>: <span class="built_in">string</span> = <span class="string">&#x27;Stark&#x27;</span></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">firstName: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">firstName</span> = firstName</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">GrandSon</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Son</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">firstName: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">super</span>(firstName)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">get</span> <span class="title function_">myLastName</span>() &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">lastName</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">set</span> <span class="title function_">myLastName</span>(<span class="params">name: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">firstName</span> === <span class="string">&#x27;Tony&#x27;</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">lastName</span> = name</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;Unable to change myLastName&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> grandSon = <span class="keyword">new</span> <span class="title class_">GrandSon</span>(<span class="string">&#x27;Tony&#x27;</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(grandSon.<span class="property">myLastName</span>) <span class="comment">// =&gt; &quot;Stark&quot;</span></span><br><span class="line">grandSon.<span class="property">myLastName</span> = <span class="string">&#x27;Rogers&#x27;</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(grandSon.<span class="property">myLastName</span>) <span class="comment">// =&gt; &quot;Rogers&quot;</span></span><br><span class="line"><span class="keyword">const</span> grandSon1 = <span class="keyword">new</span> <span class="title class_">GrandSon</span>(<span class="string">&#x27;Tony1&#x27;</span>)</span><br><span class="line">grandSon1.<span class="property">myLastName</span> = <span class="string">&#x27;Rogers&#x27;</span> <span class="comment">// =&gt; 控制台err: &quot;Unable to change myLastName&quot;</span></span><br></pre></td></tr></table></figure>

<h2 id="静态属性"><a href="#静态属性" class="headerlink" title="静态属性"></a>静态属性</h2><p>因为这些属性存在于类这个特殊的对象上，而不是类的实例上，所以我们可以直接通过类访问静态属性，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyArray</span> &#123;</span><br><span class="line">  <span class="keyword">static</span> displayName = <span class="string">&#x27;MyArray&#x27;</span></span><br><span class="line">  <span class="keyword">static</span> <span class="title function_">isArray</span>(<span class="params">obj: <span class="built_in">unknown</span></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">toString</span>.<span class="title function_">call</span>(obj).<span class="title function_">slice</span>(<span class="number">8</span>, -<span class="number">1</span>) === <span class="string">&#x27;Array&#x27;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">MyArray</span>.<span class="property">displayName</span>) <span class="comment">// =&gt; &quot;MyArray&quot;</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">MyArray</span>.<span class="title function_">isArray</span>([])) <span class="comment">// =&gt; true</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">MyArray</span>.<span class="title function_">isArray</span>(&#123;&#125;)) <span class="comment">// =&gt; false</span></span><br></pre></td></tr></table></figure>

<p>这里分别调用了类的静态属性和静态方法。</p>
<blockquote>
<p>注意：上边我们提到了不依赖实例 this 上下文的方法就可以定义成静态方法，这就意味着需要显式注解 this 类型才可以在静态方法中使用 this；非静态方法则不需要显式注解 this 类型，因为 this 的指向默认是类的实例。</p>
</blockquote>
<h2 id="抽象类"><a href="#抽象类" class="headerlink" title="抽象类"></a>抽象类</h2><p>抽象类是一种不能被实例化仅能被子类继承的特殊类。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">Adder</span> &#123;</span><br><span class="line">  <span class="keyword">abstract</span> <span class="attr">x</span>: <span class="built_in">number</span></span><br><span class="line">  <span class="keyword">abstract</span> <span class="attr">y</span>: <span class="built_in">number</span></span><br><span class="line">  <span class="keyword">abstract</span> <span class="title function_">add</span>(): <span class="built_in">number</span></span><br><span class="line">  displayName = <span class="string">&#x27;Adder&#x27;</span></span><br><span class="line">  <span class="title function_">addTwice</span>(): <span class="built_in">number</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> (<span class="variable language_">this</span>.<span class="property">x</span> + <span class="variable language_">this</span>.<span class="property">y</span>) * <span class="number">2</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">NumAdder</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Adder</span> &#123;</span><br><span class="line">  <span class="attr">x</span>: <span class="built_in">number</span></span><br><span class="line">  <span class="attr">y</span>: <span class="built_in">number</span></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">x: <span class="built_in">number</span>, y: <span class="built_in">number</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">super</span>()</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">x</span> = x</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">y</span> = y</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="title function_">add</span>(): <span class="built_in">number</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">x</span> + <span class="variable language_">this</span>.<span class="property">y</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> numAdder = <span class="keyword">new</span> <span class="title class_">NumAdder</span>(<span class="number">1</span>, <span class="number">2</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(numAdder.<span class="property">displayName</span>) <span class="comment">// =&gt; &quot;Adder&quot;</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(numAdder.<span class="title function_">add</span>()) <span class="comment">// =&gt; 3</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(numAdder.<span class="title function_">addTwice</span>()) <span class="comment">// =&gt; 6</span></span><br></pre></td></tr></table></figure>

<p>实际上，我们也可以定义一个描述对象结构的接口类型抽象类的结构，并通过 implements 关键字约束类的实现。使用接口与使用抽象类相比，区别在于接口只能定义类成员的类型，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">IAdder</span> &#123;</span><br><span class="line">  <span class="attr">x</span>: <span class="built_in">number</span></span><br><span class="line">  <span class="attr">y</span>: <span class="built_in">number</span></span><br><span class="line">  <span class="attr">add</span>: <span class="function">() =&gt;</span> <span class="built_in">number</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">NumAdder</span> <span class="keyword">implements</span> <span class="title class_">IAdder</span> &#123;</span><br><span class="line">  <span class="attr">x</span>: <span class="built_in">number</span></span><br><span class="line">  <span class="attr">y</span>: <span class="built_in">number</span></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">x: <span class="built_in">number</span>, y: <span class="built_in">number</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">x</span> = x</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">y</span> = y</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="title function_">add</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">x</span> + <span class="variable language_">this</span>.<span class="property">y</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="title function_">addTwice</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> (<span class="variable language_">this</span>.<span class="property">x</span> + <span class="variable language_">this</span>.<span class="property">y</span>) * <span class="number">2</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>interface 会在转移成 js 时抹除掉，而抽象类则会留下来。</p>
</blockquote>
<h2 id="类的类型"><a href="#类的类型" class="headerlink" title="类的类型"></a>类的类型</h2><p>类的最后一个特性——类的类型和函数类似，即在声明类的时候，其实也同时声明了一个特殊的类型（确切地讲是一个接口类型），这个类型的名字就是类名，表示类实例的类型；在定义类的时候，我们声明的除构造函数外所有属性、方法的类型就是这个特殊类型的成员。如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">A</span> &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">name: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">name</span> = name</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> <span class="attr">a1</span>: A = &#123;&#125; <span class="comment">// ts(2741) Property &#x27;name&#x27; is missing in type &#x27;&#123;&#125;&#x27; but required in type &#x27;A&#x27;.</span></span><br><span class="line"><span class="keyword">const</span> <span class="attr">a2</span>: A = &#123; <span class="attr">name</span>: <span class="string">&#x27;a2&#x27;</span> &#125; <span class="comment">// ok</span></span><br></pre></td></tr></table></figure>

<h1 id="接口类型与类型别名"><a href="#接口类型与类型别名" class="headerlink" title="接口类型与类型别名"></a>接口类型与类型别名</h1><h2 id="Interface-接口类型"><a href="#Interface-接口类型" class="headerlink" title="Interface 接口类型"></a>Interface 接口类型</h2><p>TypeScript 不仅能帮助前端改变思维方式，还能强化面向接口编程的思维和能力，而这正是得益于 Interface 接口类型。通过接口类型，我们可以清晰地定义模块内、跨模块、跨项目代码的通信规则。</p>
<p>TypeScript 对对象的类型检测遵循一种被称之为“鸭子类型”（duck typing）或者“结构化类型（structural subtyping）”的准则，即只要两个对象的结构一致，属性和方法的类型一致，则它们的类型就是一致的。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Study</span>(<span class="params">language: &#123; name: <span class="built_in">string</span>; age: () =&gt; <span class="built_in">number</span> &#125;</span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(</span><br><span class="line">    <span class="string">`ProgramLanguage <span class="subst">$&#123;language.name&#125;</span> created <span class="subst">$&#123;language.age()&#125;</span> years ago.`</span></span><br><span class="line">  )</span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">Study</span>(&#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;TypeScript&#x27;</span>,</span><br><span class="line">  <span class="attr">age</span>: <span class="function">() =&gt;</span> <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getFullYear</span>() - <span class="number">2012</span>,</span><br><span class="line">&#125;)</span><br><span class="line"><span class="title class_">Study</span>(&#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="number">2</span>, <span class="comment">// ts(2322) number 不能赋值给 string</span></span><br><span class="line">  <span class="attr">age</span>: <span class="function">() =&gt;</span> <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getFullYear</span>() - <span class="number">2012</span>,</span><br><span class="line">&#125;)</span><br><span class="line"><span class="title class_">Study</span>(&#123;</span><br><span class="line">  <span class="comment">// ts(2345) 实参(Argument)与形参(Parameter)类型不兼容，缺少必需的属性 age</span></span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;TypeScript&#x27;</span>,</span><br><span class="line">&#125;)</span><br><span class="line"><span class="title class_">Study</span>(&#123;</span><br><span class="line">  <span class="attr">id</span>: <span class="number">2</span>, <span class="comment">// ts(2345) 实参(Argument)与形参(Parameter)类型不兼容，不存在的属性 id</span></span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;TypeScript&#x27;</span>,</span><br><span class="line">  <span class="attr">age</span>: <span class="function">() =&gt;</span> <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getFullYear</span>() - <span class="number">2012</span>,</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>有意思的是，在上边的示例中，如果我们先把这个对象字面量赋值给一个变量，然后再把变量传递给函数进行调用，那么 TypeScript 静态类型检测就会仅仅检测形参类型中定义过的属性类型，而包容地忽略任何多余的属性，此时也不会抛出一个 ts(2345) 类型错误。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> ts = &#123;</span><br><span class="line">  <span class="attr">id</span>: <span class="number">2</span>,</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;TypeScript&#x27;</span>,</span><br><span class="line">  <span class="attr">age</span>: <span class="function">() =&gt;</span> <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getFullYear</span>() - <span class="number">2012</span>,</span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">Study</span>(ts) <span class="comment">// ok</span></span><br></pre></td></tr></table></figure>

<p>这并非一个疏忽或 bug，而是有意为之地将对象字面量和变量进行区别对待，我们把这种情况称之为对象字面量的 freshness。</p>
<p>内联形式的接口类型定义在语法层面与熟知的 JavaScript 解构颇为神似，所以要分清楚它们的区别：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** 纯 JavaScript 解构语法 */</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">StudyJavaScript</span>(<span class="params">&#123; name, age &#125;</span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(name, age)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/** TypeScript 里解构与内联类型混用 */</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">StudyTypeScript</span>(<span class="params">&#123; name, age &#125;: &#123; name: <span class="built_in">string</span>; age: () =&gt; <span class="built_in">number</span> &#125;</span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(name, age)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/** 纯 JavaScript 解构语法，定义别名 */</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">StudyJavaScript</span>(<span class="params">&#123; name: aliasName &#125;</span>) &#123;</span><br><span class="line">  <span class="comment">// 定义name的别名</span></span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(aliasName)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/** TypeScript */</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">StudyTypeScript</span>(<span class="params">language: &#123; name: <span class="built_in">string</span> &#125;</span>) &#123;</span><br><span class="line">  <span class="comment">// console.log(name); // 不能直接打印name</span></span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(language.<span class="property">name</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在 TypeScript 中，接口的语法和其他类型的语言并没有太大区别，我们通过如下所示代码一起看看接口是如何定义的：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">;<span class="regexp">/ ** 关键字 接口名称 */</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">ProgramLanguage</span> &#123;</span><br><span class="line">  <span class="comment">/** 语言名称 */</span></span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">  <span class="comment">/** 使用年限 */</span></span><br><span class="line">  <span class="attr">age</span>: <span class="function">() =&gt;</span> <span class="built_in">number</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在前边示例中，通过内联参数类型定义的 Study 函数就可以直接使用 ProgramLanguage 接口来定义参数 language 的类型了，或者定义变量。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">NewStudy</span>(<span class="params">language: ProgramLanguage</span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(</span><br><span class="line">    <span class="string">`ProgramLanguage <span class="subst">$&#123;language.name&#125;</span> created <span class="subst">$&#123;language.age()&#125;</span> years ago.`</span></span><br><span class="line">  )</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> <span class="title class_">TypeScript</span>: <span class="title class_">ProgramLanguage</span></span><br></pre></td></tr></table></figure>

<p>接着，我们把满足接口类型约定的一个对象字面量赋值给了这个变量:</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">TypeScript</span> = &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;TypeScript&#x27;</span>,</span><br><span class="line">  <span class="attr">age</span>: <span class="function">() =&gt;</span> <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getFullYear</span>() - <span class="number">2012</span>,</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// ok</span></span><br><span class="line"></span><br><span class="line"><span class="title class_">TypeScript</span> = &#123;&#125;</span><br><span class="line"><span class="comment">// 提示对象字面量类型 &#123;&#125; 缺少 name 和 age 属性的 ts(2739) 错误</span></span><br><span class="line"></span><br><span class="line"><span class="title class_">TypeScript</span> = &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;TypeScript&#x27;</span>,</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 提示对象字面量类型 &#123; name: string; &#125; 缺少必需的 age 属性的 ts( 2741) 错误。</span></span><br><span class="line"></span><br><span class="line"><span class="title class_">TypeScript</span> = &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="number">2</span>,</span><br><span class="line">  <span class="attr">age</span>: <span class="string">&#x27;Wrong Type&#x27;</span>,</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// ts(2322) number 类型不能赋值给 string，第 3 行会提示错误：ts(2322)string 不能赋值给函数类型</span></span><br><span class="line"></span><br><span class="line"><span class="title class_">TypeScript</span> = &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;TypeScript&#x27;</span>,</span><br><span class="line">  <span class="attr">age</span>: <span class="function">() =&gt;</span> <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getFullYear</span>() - <span class="number">2012</span>,</span><br><span class="line">  <span class="attr">id</span>: <span class="number">1</span>,</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// ts(2322) 错误：对象字面量不能赋值给 ProgramLanguage 类型的变量 TypeScript，id在ProgramLanguage类型里不存在</span></span><br></pre></td></tr></table></figure>

<h2 id="可缺省属性"><a href="#可缺省属性" class="headerlink" title="可缺省属性"></a>可缺省属性</h2><p>如果某个属性需要时可缺省，那么可以使用<code>?</code>语法来标注：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** 关键字 接口名称 */</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">OptionalProgramLanguage</span> &#123;</span><br><span class="line">  <span class="comment">/** 语言名称 */</span></span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">  <span class="comment">/** 使用年限 */</span></span><br><span class="line">  age?: <span class="function">() =&gt;</span> <span class="built_in">number</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> <span class="title class_">OptionalTypeScript</span>: <span class="title class_">OptionalProgramLanguage</span> = &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;TypeScript&#x27;</span>,</span><br><span class="line">&#125; <span class="comment">// ok</span></span><br></pre></td></tr></table></figure>

<p>当属性被标注为可缺省后，它的类型就变成了显式指定的类型与 undefined 类型组成的联合类型，比如示例中 OptionalTypeScript 的 age 属性类型就变成了<code>(() =&gt; number) | undefined</code></p>
<p>但是和前面的可缺省参数一样，可缺省属性并不等同于<code>xxx | undefined</code>。</p>
<p>既然值可能是 undefined ，如果我们需要对该对象的属性或方法进行操作，就可以使用类型守卫或 Optional Chain，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="title class_">OptionalTypeScript</span>.<span class="property">age</span> === <span class="string">&#x27;function&#x27;</span>) &#123;</span><br><span class="line">  <span class="title class_">OptionalTypeScript</span>.<span class="title function_">age</span>()</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// or</span></span><br><span class="line"><span class="title class_">OptionalTypeScript</span>.<span class="property">age</span>?.()</span><br></pre></td></tr></table></figure>

<h2 id="只读属性"><a href="#只读属性" class="headerlink" title="只读属性"></a>只读属性</h2><p>我们可能还会碰到这样的场景，希望对对象的某个属性或方法锁定写操作，这时，我们可以在属性名前通过添加 readonly 修饰符的语法来标注其为只读属性：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">ReadOnlyProgramLanguage</span> &#123;</span><br><span class="line">  <span class="comment">/** 语言名称 */</span></span><br><span class="line">  <span class="keyword">readonly</span> <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">  <span class="comment">/** 使用年限 */</span></span><br><span class="line">  <span class="keyword">readonly</span> <span class="attr">age</span>: (<span class="function">() =&gt;</span> <span class="built_in">number</span>) | <span class="literal">undefined</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> <span class="title class_">ReadOnlyTypeScript</span>: <span class="title class_">ReadOnlyProgramLanguage</span> = &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;TypeScript&#x27;</span>,</span><br><span class="line">  <span class="attr">age</span>: <span class="literal">undefined</span>,</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/** ts(2540)错误，name 只读 */</span></span><br><span class="line"><span class="title class_">ReadOnlyTypeScript</span>.<span class="property">name</span> = <span class="string">&#x27;JavaScript&#x27;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>需要注意的是，这仅仅是静态类型检测层面的只读，实际上并不能阻止对对象的篡改。因为在转译为 JavaScript 之后，readonly 修饰符会被抹除。因此，任何时候与其直接修改一个对象，不如返回一个新的对象，这会是一种比较安全的实践。</p>
</blockquote>
<h2 id="定义函数类型"><a href="#定义函数类型" class="headerlink" title="定义函数类型"></a>定义函数类型</h2><p>除了对象还可以定义函数的类型：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">StudyLanguage</span> &#123;</span><br><span class="line">  (<span class="attr">language</span>: <span class="title class_">ProgramLanguage</span>): <span class="built_in">void</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/** 单独的函数实践 */</span></span><br><span class="line"><span class="keyword">let</span> <span class="title class_">StudyInterface</span>: <span class="title class_">StudyLanguage</span> = <span class="function">(<span class="params">language</span>) =&gt;</span></span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`<span class="subst">$&#123;language.name&#125;</span> <span class="subst">$&#123;language.age()&#125;</span>`</span>)</span><br></pre></td></tr></table></figure>

<p>实际上，我们很少使用接口类型来定义函数的类型，更多使用内联类型或类型别名配合箭头函数语法来定义函数类型，比如：<code>type StudyLanguageType = (language: ProgramLanguage) =&gt; void</code></p>
<h2 id="索引签名"><a href="#索引签名" class="headerlink" title="索引签名"></a>索引签名</h2><p>在实际工作中我们经常会把对象当 Map 映射使用，比如下边代码示例中定义了索引是任意数字的对象 LanguageRankMap 和索引是任意字符串的对象 LanguageMap。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="title class_">LanguageRankMap</span> = &#123;</span><br><span class="line">  <span class="number">1</span>: <span class="string">&#x27;TypeScript&#x27;</span>,</span><br><span class="line">  <span class="number">2</span>: <span class="string">&#x27;JavaScript&#x27;</span>,</span><br><span class="line">  <span class="comment">//...</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> <span class="title class_">LanguageMap</span> = &#123;</span><br><span class="line">  <span class="title class_">TypeScript</span>: <span class="number">2012</span>,</span><br><span class="line">  <span class="title class_">JavaScript</span>: <span class="number">1995</span>,</span><br><span class="line">  <span class="comment">//...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这个时候，我们需要使用索引签名来定义上边提到的对象映射结构，并通过 “[索引名: 类型]”的格式约束索引的类型。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">LanguageRankInterface</span> &#123;</span><br><span class="line">  [<span class="attr">rank</span>: <span class="built_in">number</span>]: <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">LanguageYearInterface</span> &#123;</span><br><span class="line">  [<span class="attr">name</span>: <span class="built_in">string</span>]: <span class="built_in">number</span></span><br><span class="line">&#125;</span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">let</span> <span class="title class_">LanguageRankMap</span>: <span class="title class_">LanguageRankInterface</span> = &#123;</span><br><span class="line">    <span class="number">1</span>: <span class="string">&#x27;TypeScript&#x27;</span>, <span class="comment">// ok</span></span><br><span class="line">    <span class="number">2</span>: <span class="string">&#x27;JavaScript&#x27;</span>, <span class="comment">// ok</span></span><br><span class="line">    <span class="title class_">WrongINdex</span>: <span class="string">&#x27;2012&#x27;</span>, <span class="comment">// ts(2322) 不存在的属性名</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> <span class="title class_">LanguageMap</span>: <span class="title class_">LanguageYearInterface</span> = &#123;</span><br><span class="line">    <span class="title class_">TypeScript</span>: <span class="number">2012</span>, <span class="comment">// ok</span></span><br><span class="line">    <span class="title class_">JavaScript</span>: <span class="number">1995</span>, <span class="comment">// ok</span></span><br><span class="line">    <span class="number">1</span>: <span class="number">1970</span>, <span class="comment">// ok</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>注意：在上述示例中，数字作为对象索引时，它的类型既可以与数字兼容，也可以与字符串兼容，这与 JavaScript 的行为一致。因此，使用 0 或 ‘0’ 索引对象时，这两者等价。</p>
</blockquote>
<p>同样，我们可以使用 readonly 注解索引签名，此时将对应属性设置为只读就行，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">LanguageRankInterface</span> &#123;</span><br><span class="line">  <span class="keyword">readonly</span> [<span class="attr">rank</span>: <span class="built_in">number</span>]: <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">LanguageYearInterface</span> &#123;</span><br><span class="line">  <span class="keyword">readonly</span> [<span class="attr">name</span>: <span class="built_in">string</span>]: <span class="built_in">number</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>注意：虽然属性可以与索引签名进行混用，但是属性的类型必须是对应的数字索引或字符串索引的类型的子集，否则会出现错误提示。</p>
</blockquote>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">StringMap</span> &#123;</span><br><span class="line">  [<span class="attr">prop</span>: <span class="built_in">string</span>]: <span class="built_in">number</span></span><br><span class="line">  <span class="attr">age</span>: <span class="built_in">number</span> <span class="comment">// ok</span></span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span> <span class="comment">// ts(2411) name 属性的 string 类型不能赋值给字符串索引类型 number</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">NumberMap</span> &#123;</span><br><span class="line">  [<span class="attr">rank</span>: <span class="built_in">number</span>]: <span class="built_in">string</span></span><br><span class="line">  <span class="number">1</span>: <span class="built_in">string</span> <span class="comment">// ok</span></span><br><span class="line">  <span class="number">0</span>: <span class="built_in">number</span> <span class="comment">// ts(2412) 0 属性的 number 类型不能赋值给数字索引类型 string</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>另外，由于上边提到了数字类型索引的特殊性，所以我们不能约束数字索引属性与字符串索引属性拥有截然不同的类型，具体示例如下：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">LanguageRankInterface</span> &#123;</span><br><span class="line">  [<span class="attr">rank</span>: <span class="built_in">number</span>]: <span class="built_in">string</span> <span class="comment">// ts(2413) 数字索引类型 string 类型不能赋值给字符串索引类型 number</span></span><br><span class="line">  [<span class="attr">prop</span>: <span class="built_in">string</span>]: <span class="built_in">number</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果我们确实需要使用 age 是 number 类型、其他属性类型是 string 的对象数据结构，应该如何定义它的类型且不提示错误呢？那么就需要使用到多个接口了，用法在下一章讲到。</p>
<h2 id="继承-1"><a href="#继承-1" class="headerlink" title="继承"></a>继承</h2><p>在 TypeScript 中，接口类型可以继承和被继承，比如我们可以使用如下所示的 extends 关键字实现接口的继承。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">DynamicLanguage</span> <span class="keyword">extends</span> <span class="title class_">ProgramLanguage</span> &#123;</span><br><span class="line">  <span class="attr">rank</span>: <span class="built_in">number</span> <span class="comment">// 定义新属性</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">TypeSafeLanguage</span> <span class="keyword">extends</span> <span class="title class_">ProgramLanguage</span> &#123;</span><br><span class="line">  <span class="attr">typeChecker</span>: <span class="built_in">string</span> <span class="comment">// 定义新的属性</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/** 继承多个 */</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">TypeScriptLanguage</span> <span class="keyword">extends</span> <span class="title class_">DynamicLanguage</span>, <span class="title class_">TypeSafeLanguage</span> &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;TypeScript&#x27;</span> <span class="comment">// 用原属性类型的兼容的类型(比如子集)重新定义属性</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>注意：我们仅能使用兼容的类型覆盖继承的属性</strong>:</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** ts(6196) 错误的继承，name 属性不兼容 */</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">WrongTypeLanguage</span> <span class="keyword">extends</span> <span class="title class_">ProgramLanguage</span> &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">number</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述代码中，因为 ProgramLanguage 的 name 属性是 string 类型，WrongTypeLanguage 的 name 属性是 number，二者不兼容，所以不能继承，也会提示一个 ts(6196) 错误。</p>
<h2 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h2><p>我们还可与让类实现某个接口</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">LanguageClass</span> <span class="keyword">implements</span> <span class="title class_">ProgramLanguage</span> &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span> = <span class="string">&#x27;&#x27;</span></span><br><span class="line">  age = <span class="function">() =&gt;</span> <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getFullYear</span>() - <span class="number">2012</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="Type-类型别名"><a href="#Type-类型别名" class="headerlink" title="Type 类型别名"></a>Type 类型别名</h1><p>接口类型的一个作用是将内联类型抽离出来，从而实现类型可复用。其实，我们也可以使用类型别名接收抽离出来的内联类型实现复用。此时，我们可以通过如下所示“type 别名名字 &#x3D; 类型定义”的格式来定义类型别名。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> <span class="title class_">LanguageType</span> = &#123;</span><br><span class="line">  <span class="comment">/** 以下是接口属性 */</span></span><br><span class="line">  <span class="comment">/** 语言名称 */</span></span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">  <span class="comment">/** 使用年限 */</span></span><br><span class="line">  <span class="attr">age</span>: <span class="function">() =&gt;</span> <span class="built_in">number</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>此外，针对接口类型无法覆盖的场景，比如组合类型、交叉类型（下一章讲到），我们只能使用类型别名来接收，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** 联合 */</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">MixedType</span> = <span class="built_in">string</span> | <span class="built_in">number</span></span><br><span class="line"><span class="comment">/** 交叉 */</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">IntersectionType</span> = &#123; <span class="attr">id</span>: <span class="built_in">number</span>; <span class="attr">name</span>: <span class="built_in">string</span> &#125; &amp; &#123;</span><br><span class="line">  <span class="attr">age</span>: <span class="built_in">number</span></span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/** 提取接口属性类型 */</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">AgeType</span> = <span class="title class_">ProgramLanguage</span>[<span class="string">&#x27;age&#x27;</span>]</span><br></pre></td></tr></table></figure>

<blockquote>
<p>注意：类型别名，诚如其名，即我们仅仅是给类型取了一个新的名字，并不是创建了一个新的类型。</p>
</blockquote>
<h2 id="Interface-与-Type-的区别"><a href="#Interface-与-Type-的区别" class="headerlink" title="Interface 与 Type 的区别"></a>Interface 与 Type 的区别</h2><p>实际上，在大多数的情况下使用接口类型和类型别名的效果等价，但是在某些特定的场景下这两者还是存在很大区别。比如，重复定义的接口类型，它的属性会叠加，这个特性使得我们可以极其方便地对全局变量、第三方库的类型做扩展，如下代码所示：</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">Language</span> &#123;</span><br><span class="line">  <span class="attr">id</span>: <span class="built_in">number</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Language</span> &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> <span class="attr">lang</span>: <span class="title class_">Language</span> = &#123;</span><br><span class="line">  <span class="attr">id</span>: <span class="number">1</span>, <span class="comment">// ok</span></span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;name&#x27;</span>, <span class="comment">// ok</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述代码中，先后定义的两个 Language 接口属性被叠加在了一起，此时我们可以赋值给 lang 变量一个同时包含 id 和 name 属性的对象。不过，如果我们重复定义类型别名，如下代码所示，则会提示一个 ts(2300) 错误。</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** ts(2300) 重复的标志 */</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">Language</span> = &#123;</span><br><span class="line">  <span class="attr">id</span>: <span class="built_in">number</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/** ts(2300) 重复的标志 */</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">Language</span> = &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> <span class="attr">lang</span>: <span class="title class_">Language</span> = &#123;</span><br><span class="line">  <span class="attr">id</span>: <span class="number">1</span>,</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;name&#x27;</span>,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>下一章讲解：联合类型、交叉类型、枚举类型、泛型</p>
</blockquote>

    </div>

    
    
    

    <footer class="post-footer">
          

<div class="post-copyright">
<ul>
  <li class="post-copyright-author">
      <strong>本文作者： </strong>Wyatex
  </li>
  <li class="post-copyright-link">
      <strong>本文链接：</strong>
      <a href="https://wyatex.online/TypeScript/ts%E7%AC%94%E8%AE%B0%EF%BC%882%EF%BC%89%EF%BC%9A%E5%87%BD%E6%95%B0%E3%80%81%E7%B1%BB%E3%80%81%E6%8E%A5%E5%8F%A3%E7%B1%BB%E5%9E%8B%E5%92%8C%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D/" title="ts笔记（2）：函数、类、接口类型和类型别名">https://wyatex.online/TypeScript/ts笔记（2）：函数、类、接口类型和类型别名/</a>
  </li>
  <li class="post-copyright-license">
      <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>

          <div class="post-tags">
              <a href="/tags/%E5%89%8D%E7%AB%AF/" rel="tag"># 前端</a>
              <a href="/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/" rel="tag"># 学习笔记</a>
              <a href="/tags/TypeScript/" rel="tag"># TypeScript</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/TypeScript/ts%E7%AC%94%E8%AE%B0%EF%BC%881%EF%BC%89%EF%BC%9A%E6%90%AD%E5%BB%BA%E5%92%8C%E4%B8%80%E4%BA%9B%E5%9F%BA%E7%A1%80%E7%B1%BB%E5%9E%8B/" rel="prev" title="ts笔记（1）：搭建和一些基础类型">
                  <i class="fa fa-angle-left"></i> ts笔记（1）：搭建和一些基础类型
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/TypeScript/ts%E7%AC%94%E8%AE%B0%EF%BC%883%EF%BC%89%EF%BC%9A%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B%E3%80%81%E4%BA%A4%E5%8F%89%E7%B1%BB%E5%9E%8B%E3%80%81%E6%9E%9A%E4%B8%BE%E7%B1%BB%E5%9E%8B%E3%80%81%E6%B3%9B%E5%9E%8B/" rel="next" title="ts笔记（3）：联合类型、交叉类型、枚举类型、泛型">
                  ts笔记（3）：联合类型、交叉类型、枚举类型、泛型 <i class="fa fa-angle-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">

  <div class="copyright">
    &copy; 2019 – 
    <span itemprop="copyrightYear">2024</span>
    <span class="with-love">
      <i class="fa fa-heart"></i>
    </span>
    <span class="author" itemprop="copyrightHolder">Wyatex</span>
  </div>
<div class="busuanzi-count">
    <span class="post-meta-item" id="busuanzi_container_site_uv">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-item" id="busuanzi_container_site_pv">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="总访问量">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>

    </div>
  </footer>

  
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script size="300" alpha="0.6" zIndex="-1" src="/lib/ribbon.js/dist/ribbon.min.js"></script>
  <script src="/lib/animejs/lib/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="/lib/@next-theme/pjax/pjax.min.js" integrity="sha256-vxLn1tSKWD4dqbMRyv940UYw4sXgMtYcK6reefzZrao=" crossorigin="anonymous"></script>
  <script src="/lib/@fancyapps/ui/dist/fancybox/fancybox.umd.js" integrity="sha256-q8XkJ6dj5VwSvzI8+nATCHHQG+Xv/dAZBCgqmu93zOY=" crossorigin="anonymous"></script>
  <script src="/lib/lozad/dist/lozad.min.js" integrity="sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script><script src="/js/pjax.js"></script>

  <script src="/lib/hexo-generator-searchdb/dist/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>




  <script src="/js/third-party/fancybox.js"></script>



  
  <script data-pjax async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>





</body>
</html>
